#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <json/json.h>
#include <ctime>

// 安装JSONCPP库
// ubuntu：sudo apt-get install libjsoncpp-dev
// Centos: sudo yum install jsoncpp-devel
// 编译代码：-ljsoncpp

//#define SELF 1

namespace protocol_ns
{

    // 1. 你怎么知道我发过来的一个数据是完整的呢？

    // 2. 那么我发的时候，按照报文 = 报头 + 有效载荷   形式例如: "len\r\n{........}\r\n"  (len有效载荷的长度， {.........}有效载荷, 以\r\n)
    // 将来给你一个有效载荷，你给我按照以上格式进行打包成这种报文形式发送
    static const std::string protsep = " ";
    const static std::string sep = "\r\n"; // 分隔符
    std::string EnCode(const std::string &json_str)
    {
        int json_str_len = json_str.size();
        std::string proto_str = std::to_string(json_str_len);
        proto_str += sep;
        proto_str += json_str;
        proto_str += sep;
        return proto_str;
    }

    // 3. 现在我读到的inbuffer, 有可能不是完整的， 可能不足一个， 可能超过了一个完整的， 包装上了报头，现在可以确定怎么读到一个完整的了
    // 如果不足一个完整的报头长度 即 < total时， continue，继续读， 当读到的字符串长度 > total了，我们在inbuffer里面截取一个完整的长度走，就可以了

    // 返回值位空串， 继续读， 否则就一定返回了一个完整的报文
    std::string DeCode(std::string &inbuffer)
    {
        //"len\r\n{........}\r\n"
        auto pos = inbuffer.find(sep);
        if (pos == std::string::npos)
            return std::string();
        std::string len_str = inbuffer.substr(0, pos);
        int len = std::stoi(len_str);
        int total = len_str.size() + len + 2 * sep.size(); // 一个完整的报文的长度
        if (inbuffer.size() < total)
            return std::string();
        // 截取出来一个完整的报文后，在inbuffer里面移除掉
        std::string packstr = inbuffer.substr(pos + sep.size(), len);
        inbuffer.erase(0, total);
        return packstr;
    }

    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char oper)
            : _x(x), _y(y), _oper(oper)
        {
        }
        ~Request()
        {
        }
        // 序列化
        void Serialize(std::string *out)
        {
            //"x op y"
#ifdef SELF
            std::string data_x = std::to_string(_x);
            std::string data_y = std::to_string(_y);
            *out = data_x + protsep + _oper + protsep + data_y;
#else
            // 1. 将结构化数据存到万能对象Value里面
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;
            // 2. 将root数据进行序列化(write)
            // Json::StyledWriter writer;
            Json::FastWriter Writer;
            *out = Writer.write(root);
#endif
        }
        // 反序列化
        bool Deserialize(std::string &in)
        {
#ifdef SELF
            //"x op y"
            auto left = in.find(protsep);
            if (left == std::string::npos)
                return false;
            auto right = in.rfind(protsep);
            if (right == std::string::npos)
                return false;
            if (left + protsep.size() + 1 != right)
                return false;
            std::string left_data = in.substr(0, left);
            if (left_data.empty())
                return false;
            std::string right_data = in.substr(right + protsep.size());
            if (right_data.empty())
                return false;
            _x = std::stoi(left_data);
            _y = std::stoi(right_data);
            _oper = in[right - 1];
            return true;
#else
            // 1. 将字符串反序列化
            Json::Value root;
            Json::Reader reader;
            reader.parse(in.c_str(), root);
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
#endif
        }

    public:
        int _x;
        int _y;
        char _oper; // "+-*/%" _x _oper _y
    }; // 结构化数据，序列化---字符串   字符串----反序列

    class Response
    {
    public:
        Response()
        {
        }
        Response(int result, int code)
            : _result(result), _code(code)
        {
        }
        ~Response()
        {
        }
        // 序列化
        void Serialize(std::string *out)
        {
#ifdef SELF
            //"result code"
            std::string result_str = std::to_string(_result);
            std::string code_str = std::to_string(_code);
            *out = result_str + protsep + code_str;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter Writer;
            *out = Writer.write(root);
#endif
        }
        // 反序列化
        bool Deserialize(std::string &in)
        {
#ifdef SELF
            //"result code"
            auto mid = in.find(protsep);
            if (mid == std::string::npos)
                return false;
            std::string result_data = in.substr(0, mid);
            if (result_data.empty())
                return false;
            std::string code_data = in.substr(mid + 1);
            _result = std::stoi(result_data);
            _code = std::stoi(code_data);
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(in.c_str(), root);
            _result = root["result"].asInt();
            _code = root["code"].asInt();
#endif
        }

    public:
        int _result; // 结果
        int _code;   // 0:success 1: 除0 2: 非法操作 3. 4. 5
    }; // 结构化数据，序列化---字符串   字符串----反序列

    // 生产Responce 和 Request工厂
    class Factory
    {
    public:
        Factory()
        {
            srand(time(nullptr) ^ getpid());
            _opers = "+/*/%^&|";
        }
        std::shared_ptr<Request> BuildRequest()
        {
            int x = rand() % 10 + 1;
            usleep(x * 10);
            int y = rand() % 5;
            usleep(y * x * 5);
            char oper = _opers[rand() % _opers.size()];
            std::shared_ptr<Request> req = std::make_shared<Request>(x, y, oper);
            return req;
        }
        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }

    private:
        std::string _opers;
    };
} // namespace protocol_ns
